namespace ClassyBlog.ExtensionMethods.Specs.Unit
{
    using System;
    using System.Collections.Generic;

    using Machine.Specifications;

    [Subject(typeof(ObjectExtensions))]
    public class when_casting_to_another_valid_type
    {
        static object dummyObject;
        static DummyObject strongDummyObject;

        Establish contenxt = () => dummyObject = new DummyObject();

        Because of = () => strongDummyObject = dummyObject.To<DummyObject>();

        It should_be_able_to_cast = () => strongDummyObject.ShouldNotBeNull();

        private class DummyObject
        {
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_casting_as_another_valid_type
    {
        static object dummyObject;
        static DummyObject strongDummyObject;

        Establish contenxt = () => dummyObject = new DummyObject();

        Because of = () => strongDummyObject = dummyObject.As<DummyObject>();

        It should_be_able_to_cast = () => strongDummyObject.ShouldNotBeNull();

        private class DummyObject
        {
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class
        when_trying_to_invoke_method_of_an_null_object_without_default_value
    {
        static DummyObject dummy;
        static string result;

        Establish context = () => dummy = null;

        Because of = () => result = dummy.Try(() => dummy.Foo());

        It should_return_type_default = () =>
            result.ShouldEqual(default(string));

        private class DummyObject
        {
            public string Foo()
            {
                return "Bar";
            }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class
        when_trying_to_invoke_method_of_an_null_object_with_default_value
    {
        static DummyObject dummy;
        static string result;

        Establish context = () => dummy = null;

        Because of = () => result = dummy.Try(() => dummy.Foo(), "baz");

        It should_return_type_default = () => result.ShouldEqual("baz");

        private class DummyObject
        {
            public string Foo()
            {
                return "Bar";
            }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_trying_to_invoke_method_of_an_object
    {
        static DummyObject dummy;
        static string result;

        Establish context = () => dummy = new DummyObject();

        Because of = () => result = dummy.Try(() => dummy.Foo());

        It should_return_the_method_result = () => result.ShouldEqual("Bar");

        private class DummyObject
        {
            public string Foo()
            {
                return "Bar";
            }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_getting_property_as_dynamic_property
    {
        static DummyObject dummyObject;
        static string value;

        Establish context = () => dummyObject = new DummyObject
                                                    {
                                                        Foo = "bar"
                                                    };

        Because of = () => value = dummyObject.Property().Foo;

        It should_get = () => value.ShouldEqual("bar");

        private class DummyObject
        {
            public string Foo { get; set; }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_setting_property_as_dynamic_property
    {
        static DummyObject dummyObject;

        Establish context = () => dummyObject = new DummyObject();

        Because of = () => dummyObject.Property().Foo = "bar";

        It should_set = () => dummyObject.Foo.ShouldEqual("bar");

        private class DummyObject
        {
            public string Foo { get; set; }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_exporting_a_null_object_as_dictionary
    {
        static DummyObject dummyObject;
        static Exception exception;

        Establish context = () => dummyObject = null;

        Because of = () => exception =
            Catch.Exception(() => dummyObject.ToDictionary());

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();

        private class DummyObject
        {
            public string Foo { get; set; }

            public string Bar { get; set; }

            public string Baz { get; set; }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_exported_as_dictionary
    {
        static DummyObject dummyObject;
        static IDictionary<string, object> result;

        Establish context = () => dummyObject = new DummyObject();

        Because of = () => result = dummyObject.ToDictionary();

        It should_have_property_name_as_key = () =>
        {
            result.ContainsKey("Foo").ShouldBeTrue();
            result.ContainsKey("Bar").ShouldBeTrue();
            result.ContainsKey("Baz").ShouldBeTrue();
        };

        private class DummyObject
        {
            public string Foo { get; set; }

            public string Bar { get; set; }

            public string Baz { get; set; }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_trying_to_merge_for_a_null_object
    {
        static DummyObject dummyObject1;
        static DummyObject dummyObject2;
        static Exception exception;

        Establish context = () =>
        {
            dummyObject1 = null;
            dummyObject2 = new DummyObject();
        };

        Because of = () => exception =
            Catch.Exception(() => dummyObject1.Merge(dummyObject2));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();

        private class DummyObject
        {
            public string Foo { get; set; }

            public string Bar { get; set; }

            public string Baz { get; set; }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_trying_to_merge_with_a_null_object
    {
        static DummyObject dummyObject1;
        static DummyObject dummyObject2;
        static Exception exception;

        Establish context = () =>
        {
            dummyObject1 = new DummyObject();
            dummyObject2 = null;
        };

        Because of = () => exception =
            Catch.Exception(() => dummyObject1.Merge(dummyObject2));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();

        private class DummyObject
        {
            public string Foo { get; set; }

            public string Bar { get; set; }

            public string Baz { get; set; }
        }
    }

    [Subject(typeof(ObjectExtensions))]
    public class when_merged
    {
        static DummyObject dummyObject1;
        static DummyObject dummyObject2;

        Establish context = () =>
        {
            dummyObject1 = new DummyObject { Foo = "1", Bar = "2", Baz = "3" };
            dummyObject2 = new DummyObject { Foo = "4", Bar = "5", Baz = "6" };
        };

        Because of = () => dummyObject1.Merge(dummyObject2);

        It should_replace_existing_value = () =>
        {
            dummyObject1.Foo.ShouldEqual("4");
            dummyObject1.Bar.ShouldEqual("5");
            dummyObject1.Baz.ShouldEqual("6");
        };

        private class DummyObject
        {
            public string Foo { get; set; }

            public string Bar { get; set; }

            public string Baz { get; set; }
        }
    }
}